iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
AI & Data

用R語言玩轉文字探勘系列 第 28

[Day 28] 用R語言玩轉文字探勘案例 - 清資料與斷詞篇

  • 分享至 

  • xImage
  •  

文字探勘應用案例

應用案例 - 清資料與斷詞

我們來看要如何處理爬下的資料吧!

這次我們會應用最近正在風口浪尖的中研院ckip小組開發出的斷詞系統,所以開始時要載入 python 環境才行。

library(tidyverse)
library(tidytext)
library(reticulate)
version <- "3.9.12"
virtualenv_create("my-environment", version = version)

## virtualenv: my-environment

use_virtualenv("my-environment")
os = import("os")
os$listdir(".")
py_available() 
## [1] TRUE

確定ok後,接著讀入資料。同時,我們也載入前面提過的停止詞資料。

df_speech_ten <- read_rds("data/國慶演說/df_speech_ten.rds")
df_stopwords <- read_table("data/df_stopword.txt", col_names = F) %>%
  rename(id = 1, text_segment = 2) %>% select(text_segment)
df_speech_ten %>% head(5)

## # A tibble: 5 × 3
##   year   url                                                                 text                                                                  
##   <chr>  <chr>                                                               <chr>                                                                 
## 1 八十六 https://zh.wikisource.org/wiki/總統蒞臨中華民國八十六年國慶大會致詞 "  大會主席、各位貴賓、各位親愛的父老兄弟姐妹:\n  今天是中華民國…
## 2 八十七 https://zh.wikisource.org/wiki/總統蒞臨中華民國八十七年國慶大會致詞 "  大會主席、各位貴賓、各位親愛的父老兄弟姊妹:\n  今天是中華民國…
## 3 八十八 https://zh.wikisource.org/wiki/總統蒞臨中華民國八十八年國慶大會致詞 "  各位女士、各位先生:\n  今天是中華民國八十八年國慶日。每年的這…
## 4 八十九 https://zh.wikisource.org/wiki/總統蒞臨中華民國八十九年國慶大會致詞 "  各位貴賓、各位女士、各位先生:\n  今天是中華民國八十九年國慶,…
## 5 九十   https://zh.wikisource.org/wiki/總統蒞臨中華民國九十年國慶大會致詞   "  各位貴賓、各位女士、各位先生:\n  今天是中華民國九十歲的生日,…

下一步就是斷詞前的資料清理。這次我們做了幾個步驟,先是去除半形與全形空白、分行、tab等。接著則是新增一個重要欄位:西元紀年。因為原文的年份是民國紀年,而且用法又很紛亂,往後在排序和視覺化時將會遇上問題,因此有必要抽取出西元紀年。

具體做法是先提出年份的十位數,接著提出年份的個位數,最後再用數學乘法把兩者整合,加上1911後大功告成。

稍後,我們也補上演講的總統名稱,這樣可以增添後面分析的維度,不僅僅限於年份而已。前面有介紹過要把小寫的台換成大寫的臺,這步驟可以避免日後分析出是。

還有一個關鍵步驟:以句子(sentencese)為單位拆分演說。為什麼要做這一步呢?其實,一般不會想到要做這一步,也不一定要做。因為很多語料本來就有內建章節的概念,無論是學術論文,或者是輕小說,都有明確的結構,但像是新聞還有這次的演說詞沒有,平常這不會是問題,因為我們會有很多很多媒體可以爬,因此資料量很大,但這次我們只有短短二十多年的資料,算是很小的樣本,因此當我們需要一個章節的架構時,就會自己區分,而我的分法就是句子。

df_speech_clean <- df_speech_ten %>%
  mutate(text = str_remove_all(text," | |\\n|\\t|\\r")) %>%
  mutate(year_ten = str_sub(year, 1, 2)) %>%
  mutate(year_zero = str_sub(year, 3, 3)) %>%
  mutate(year_ten = case_when(year_ten == "八十" ~ 80,
                              year_ten == "九十" ~ 90,
                              year_ten %in% c("一百","一○") ~ 100,
                              year_ten == "一一" ~ 110,
                              TRUE ~ as.double(NA))) %>%
  mutate(year_zero = case_when(year_zero == "一" ~ 1,
                               year_zero == "二" ~ 2,
                               year_zero == "三" ~ 3,
                               year_zero == "四" ~ 4,
                               year_zero == "五" ~ 5,
                               year_zero == "六" ~ 6,
                               year_zero == "七" ~ 7,
                               year_zero == "八" ~ 8,
                               year_zero == "九" ~ 9,
                               year_zero %in% c("","○") ~ 0,
                               TRUE ~ as.double(NA))) %>%
  mutate(year_full = year_ten + year_zero + 1911) %>%
  select(year_full, year, url, text) %>%
  mutate(president = case_when(year_full >= 2016 ~ "蔡English",
                               year_full >= 2008 ~ "馬英九",
                               year_full >= 2000 ~ "陳水扁",
                               year_full >= 1997 ~ "李登輝",
                               TRUE ~ "check")) %>%
  mutate(text = str_replace_all(text, "台灣", "臺灣")) %>% 
  unnest_tokens(sentence, text, token = "sentences") %>%
  group_by(president) %>% mutate(sentence_id = row_number()) %>% ungroup() %>%
  select(year_full, year, president, sentence_id, sentence)

df_speech_clean %>% head(5)

## # A tibble: 5 × 5
##   year_full year   president sentence_id sentence                                                                                                   
##       <dbl> <chr>  <chr>           <int> <chr>                                                                                                      
## 1      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國八十六年國慶日,海內外同胞用熱烈的活動,慶祝我們…
## 2      1997 八十六 李登輝              2 八十六年來,中華民國經歷了許多的挫折和危難,但是,在全體同胞的精誠團結、齊心努力下,終能一再克服挑戰,衝破…
## 3      1997 八十六 李登輝              3 今天,在政治上,我們已經實現了「主權在民」的理想,昂然邁進全民民主的新時代;在經濟上,我們不但締造了舉世矚…
## 4      1997 八十六 李登輝              4 然而,歷史的巨輪不斷向前,國家的發展也永無止境。                                                           
## 5      1997 八十六 李登輝              5 面對即將來臨的二十一世紀,我們不能自滿於既有的成就,而必須以更前瞻的思維,和更積極的作為,致力改革,推動建…

# df_speech_clean %>% write_rds("data/df_speech_clean.rds")

下一步就可以準備斷詞了!我們先載入ckip套件,接著讀取模型檔。

### 斷詞預備
ckip <- import("ckiptagger")
# 接著讀取模型檔
ws = ckip$WS("ckip/data") # 斷詞
pos = ckip$POS("ckip/data") # 詞性
ner = ckip$NER("ckip/data") # 實體辨識

### ckip
df_speech_seg <- df_speech_clean %>%
  # mutate(text = str_remove_all(text, "\\n|\\r|\\t|:| | ")) %>%
  # mutate(text = str_remove_all(text, "[a-zA-Z0-9]+")) %>%
  mutate(text_segment= ws(sentence)) %>%
  mutate(text_POS = pos(text_segment))

df_speech_seg %>% head(5)

## # A tibble: 5 × 7
##   year_full year   president sentence_id sentence                                                                              text_segment text_POS
##       <dbl> <chr>  <chr>           <int> <chr>                                                                                 <list>       <list>  
## 1      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國八十六年國慶日,海內外同胞… <chr [46]>   <chr>   
## 2      1997 八十六 李登輝              2 八十六年來,中華民國經歷了許多的挫折和危難,但是,在全體同胞的精誠團結、齊心努力下,… <chr [44]>   <chr>   
## 3      1997 八十六 李登輝              3 今天,在政治上,我們已經實現了「主權在民」的理想,昂然邁進全民民主的新時代;在經濟上… <chr [101]>  <chr>   
## 4      1997 八十六 李登輝              4 然而,歷史的巨輪不斷向前,國家的發展也永無止境。                                      <chr [15]>   <chr>   
## 5      1997 八十六 李登輝              5 面對即將來臨的二十一世紀,我們不能自滿於既有的成就,而必須以更前瞻的思維,和更積極的… <chr [61]>   <chr>

完成斷詞、貼上詞性標籤,接著利用unnest()將list-column拆開,然後處理詞性的名稱,最後再輸出,就可以等著迎接下一步。

# df_speech_seg %>% write_rds("data/df_speech_seg.rds")
# df_speech_seg <- read_rds("data/df_speech_seg.rds")

### POS結果
df_speech_seg_unnest <- df_speech_seg %>%
  mutate(text_segment_l = map_dbl(text_segment, function(x){x %>% length()}),
         text_POS_l = map_dbl(text_POS, function(x){x %>% length()})) %>%
  filter(text_segment_l == text_POS_l) %>%
  filter(text_segment_l != 0) %>%
  unnest(c(text_segment, text_POS)) %>%
  mutate(text_POS = case_when(
    str_detect(text_POS, "CATEGORY") ~ "Puncuation",
    str_detect(text_POS, "WHITESPACE") ~ "Whitespace",
    str_detect(text_POS, "^D") ~ "Adverb",
    str_detect(text_POS, "^N") ~ "Noun",
    str_detect(text_POS, "^C") ~ "Conjunction",
    str_detect(text_POS, "^V") ~ "Verb",
    text_POS == "A" ~ "Adjective",
    text_POS == "FW" ~ "FW",
    text_POS %in% c("I","P","T") ~ "IPT",
    text_POS %in% c("DE","SHI") ~ "DESHI",
    TRUE ~ "Others"
  )) %>%
  filter(!str_detect(text_segment, "[0-9]"))

df_speech_seg_unnest %>% head(5)

## # A tibble: 5 × 9
##   year_full year   president sentence_id sentence                                                    text_segment text_POS text_segment_l text_POS_l
##       <dbl> <chr>  <chr>           <int> <chr>                                                       <chr>        <chr>             <dbl>      <dbl>
## 1      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國… 大會         Noun                 46         46
## 2      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國… 主席         Noun                 46         46
## 3      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國… 、           Puncuat…             46         46
## 4      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國… 各位         Noun                 46         46
## 5      1997 八十六 李登輝              1 大會主席、各位貴賓、各位親愛的父老兄弟姐妹:今天是中華民國… 貴賓         Noun                 46         46

# df_speech_seg_unnest %>% write_rds("data/df_speech_seg_unnest.rds")

上一篇
[Day 27] 用R語言玩轉文字探勘案例 - 架構與資料準備篇
下一篇
[Day 29] 用R語言玩轉文字探勘案例 - 分析篇
系列文
用R語言玩轉文字探勘30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言